package entities;

import util.BigPrime;
import util.CountPred;
import eduni.simjava.Sim_entity;
import eduni.simjava.Sim_event;
import eduni.simjava.Sim_negexp_obj;
import eduni.simjava.Sim_port;
import eduni.simjava.Sim_system;

public class Router extends Sim_entity implements Measurable {

	private Sim_port in1, in2, out1, out2;
	
	private Sim_negexp_obj delay;

	private double chanceOfBeingOne;

	private int n;

	private double totalResponseTime;

	private double utilizationTime;

	private double total;
	
	private float mean_queue_sz = .0f;
	private int queue_samples_num = 0;
	
	public Router(String name, double mi, double chanceOfBeingOne) {
		super(name);
		
		in1 = new Sim_port("in1");
		in2 = new Sim_port("in2");
		
		out1 = new Sim_port("out1");
		out2 = new Sim_port("out2");
		
		add_port(in1);
		add_port(in2);
		add_port(out1);
		add_port(out2);
		
		delay = new Sim_negexp_obj("Time to process one bit", 1 / mi, BigPrime.getSeed());
		this.chanceOfBeingOne = chanceOfBeingOne;
	}

	@Override
	public void body() {
		Sim_event event = new Sim_event();
		
		n = 0;
		totalResponseTime = 0.0;		
		utilizationTime = 0.0;
		
		total = Sim_system.sim_clock();		
		
		while (true) {
			
			// conta eventos em fila
			CountPred cpred = new CountPred();
			sim_select(cpred, event);
			{
				mean_queue_sz = (mean_queue_sz*queue_samples_num + cpred.get_count())/
				(++queue_samples_num);
			}
			
			sim_get_next(event);
			
			//System.out.println("Router: Recebido pacote no momento " + Sim_system.sim_clock());
			
			if (event.get_tag() == -1)
				break;
			
			n++;
			// processando
			
			double processingTime = delay.sample() * event.get_tag();
			utilizationTime += processingTime;
			sim_hold(processingTime);

			if (Math.random() < chanceOfBeingOne) 
				sim_schedule(out1, 0.0, event.get_tag());
			else
				sim_schedule(out2, 0.0, event.get_tag());
			
			totalResponseTime += Sim_system.sim_clock() - event.event_time();
		}
		
		sim_schedule(out1, 0.0, -1);
		sim_schedule(out2, 0.0, -1);
		
		total = Sim_system.sim_clock() - total;
		
//		System.out.println("Router: mean N = " + Double.valueOf(meanN()).toString().replace('.', ','));
//		System.out.println("Router: mean response time = " + Double.valueOf(getR()).toString().replace('.', ','));
//		System.out.println("Router: mean service time = " + Double.valueOf(getS()).toString().replace('.', ','));
//		System.out.println("Router: utilization = " + Double.valueOf(getU()).toString().replace('.', ','));
	}

	public double getU() {
		return utilizationTime / total;
	}

	public double getS() {
		return utilizationTime / n;
	}

	public double getR() {
		return totalResponseTime / n;
	}

	public double meanN() {
		return totalResponseTime / total;
	}

	@Override
	public double meanQ() {
		return mean_queue_sz;
	}
	
}
